package davelha.client;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Vector;

import javax.swing.JOptionPane;

import davelha.common.BaseGameInterface;
import davelha.common.DaVelhaException;
import davelha.common.Player;
import davelha.common.GameControl;
import davelha.gui.JogoDaVelhaApp;
import davelha.gui.ServerStatusView;
import davelha.server.BaseServerInterface;
/**
 * 
 * @author eduardo
 * Classe que controla a aplicação que roda no cliente do jogo da velha
 */
public class Client implements Runnable {
	public static final int		STATE_START				= 0;
	public static final int		STATE_LOOKING_FOR_GAMES	= 1;
	public static final int		STATE_STOP				= 2;
	public static final int		STATE_SERVER_ERROR		= 3;
	public static final int		STATE_CLIENT_ERROR		= 4;

	// Atributos locais
	private BaseServerInterface	server					= null;
	private int					clientStatus			= -1;

	private static final int	sleepTime				= 2000; //2000;
	private Player				player					= null;
	
	private Vector<JogoDaVelhaApp> runningGames			= null;
	
	public Client(String serverLookup, Player player) throws DaVelhaException{
		String msg = null;
		
		//seta o player associado com o client
		this.player = player;
		
		//Inicializa o servidor
		try {
			server = (BaseServerInterface) Naming.lookup(serverLookup);
			//Adiciona o player no servidor
			this.player.setPlayerId(server.addPlayerToServer(this.player));
			System.out.println("Cliente connectado com o servidor: " + server.getServerName());
		} catch (MalformedURLException e) {
			msg = "Erro ao iniciar conexão com servidor: " + e.getMessage();
		} catch (RemoteException e) {
			msg = "Erro ao iniciar conexão com servidor: " + e.getMessage();			
		} catch (NotBoundException e) {
			msg = "Erro ao iniciar conexão com servidor: " + e.getMessage();			
		}
		
		if(msg != null){//erro no servidor
			clientStatus = Client.STATE_SERVER_ERROR;
			//System.out.println(msg);
			throw new DaVelhaException(msg);
		}else{
			clientStatus = Client.STATE_START;
		}
		
	}
	
	public void run(){
		
		//Inicializando o view
		ServerStatusView serverStatusView = new ServerStatusView(this, server);
		serverStatusView.setVisible(true);
	      
		Vector<String> gameIdList = null;
		Vector<BaseGameInterface> gameList = null;
		String msg = null;
		
		if(clientStatus == Client.STATE_START){
			clientStatus = Client.STATE_LOOKING_FOR_GAMES;
		
			while(clientStatus == Client.STATE_LOOKING_FOR_GAMES){				
				//Verifica os jogos existentes no cliente
				try {
					gameIdList = server.retrieveGamesRmiId();
					
					if(gameIdList != null && gameIdList.size() > 0){
						
						//Inicializa gameList
						gameList = new Vector();
						
						try {
							//recebe todos os jogos e manda para atualização da
							//tela
							for(int i = 0; i < gameIdList.size(); i++){
								BaseGameInterface game = (BaseGameInterface) 
								Naming.lookup(gameIdList.elementAt(i));
								gameList.addElement(game);
								serverStatusView.addGameInfo(gameList);
							}
						} catch (MalformedURLException e) {
							e.printStackTrace();
						} catch (NotBoundException e) {
							e.printStackTrace();
						}

					}
					
					//Verifica o estado dos jogos que o player local pediu para abrir
					Vector<BaseGameInterface> myGames = server.getPlayerGames(this.player);
					
					if(myGames != null){
						for(int i = 0; i < myGames.size(); i++){
							if(myGames.elementAt(i).getPlayer2() != null){
								if(myGames.elementAt(i).getGameState() == BaseGameInterface.STATE_WAITING_PLAYER_ONE_CONFIRMATION){
									String message = "O jogador: " 
									+ myGames.elementAt(i).getPlayer2().getName()
									+ " aceitou o seu desafio para o jogo " 
									+ myGames.elementAt(i).getGameName() 
									+ ". E ai topas?";
									int resposta = JOptionPane.showConfirmDialog(serverStatusView, message);
									
									if(resposta == 0){//sim
										//TODO: SetGAmeStatus
										server.setGameStatus(
												myGames.elementAt(i).getGameId(), 
												BaseGameInterface.STATE_GAME_START);
										
										//myGames.elementAt(i).setGameState(BaseGameInterface.STATE_GAME_PLAYER_ONE_TURN);
										
										//mostra a janela de jogo desse game
										new Thread(new GameControl(myGames.elementAt(i), 
												GameControl.I_AM_PLAYER_1)).start();
										
										//this.runningGames.addElement(runningGame);
									}else if(resposta == 1){//nao
										server.setGameStatus(
												myGames.elementAt(i).getGameId(), 
												BaseGameInterface.STATE_GAME_FINISHED);
									}else{//canelar
										server.setGameStatus(
												myGames.elementAt(i).getGameId(), 
												BaseGameInterface.STATE_WAITING_PLAYER);
									}
								}							
							}
						}
					}
					
					// Verifica o estado dos jogos que algum player remoto requisitou
					Vector<BaseGameInterface> myRequestedGames = server.getPlayerChallengeGames(this.player);					

					if(myRequestedGames != null){
						for(int i = 0; i < myRequestedGames.size(); i++){
							if(myRequestedGames.elementAt(i).getGameState() ==
								BaseGameInterface.STATE_GAME_START){
								
//								//Jogo Iniciado - Muda o estado para stoped para o P1 iniciar o jogo
								server.setGameStatus(
										myRequestedGames.elementAt(i).getGameId(), 
										BaseGameInterface.STATE_GAME_PLAYER_ONE_TURN);
								
								myRequestedGames.elementAt(i).setGameState(BaseGameInterface.STATE_GAME_PLAYER_ONE_TURN);
								
								new Thread(new GameControl(myRequestedGames.elementAt(i), 
										GameControl.I_AM_PLAYER_2)).start();
								
								
								
							}else if((myRequestedGames.elementAt(i).getGameState() ==
								BaseGameInterface.STATE_GAME_FINISHED) || 
								(myRequestedGames.elementAt(i).getGameState() ==
									BaseGameInterface.STATE_WAITING_PLAYER)
								){
								//remover o player 2 do jogo
								server.removePlayer2FromGame(
										myRequestedGames.elementAt(i).getGameId());
							}
						}
					}
					
				} catch (RemoteException e) {
					msg = "Falha ao receber a lista de jogos: " + e.getMessage();
					clientStatus = Client.STATE_SERVER_ERROR;
				}
				
				try {
					Thread.sleep(sleepTime);
				} catch (InterruptedException e) {
					msg = "Falha no controle da thread do cliente: " + e.getMessage();
					clientStatus = Client.STATE_CLIENT_ERROR;
				}
			}
			
			if(clientStatus == Client.STATE_STOP){
				System.out.println("Programa cliente finalizado corretamente.");
			}else if((clientStatus == Client.STATE_SERVER_ERROR) || 
					(clientStatus == Client.STATE_CLIENT_ERROR)){
				System.out.println("ATENCAO: Programa cliente finalizado com ERRO!\n" + msg);			
			}
		}
	}
	
	public boolean createNewGame(String gameName, Player player) throws RemoteException{
		//System.out.println("Id do player: " + player.getPlayerId());
		return server.createNewGame(gameName, player);
		
	}
	
	public boolean createNewGame(String gameName) throws RemoteException{
		return server.createNewGame(gameName, player);
	}
	
	public boolean connectToGame(int gameId){
		
		try {
			return server.connectToGame(this.player, gameId);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		
		return false;
	}
	
	
	
	/**
	 * Inicializa o cliente para conexão com o servidor informado
	 * @param args
	 */
	public static void main(String args[]){
		System.out.println("Inicializando cliente...");
		String serverLookup = "//eduardo-laptop/Server"; //endereço e objeto lookup do servidor
		
		//Criação do cliente básico
		Client client = null;
		Player player = null;
		
		try {
			player = new Player("Eduardo");
			client = new Client(serverLookup, player);
		} catch (DaVelhaException e) {
			e.printStackTrace();
		} catch (RemoteException e){
			e.printStackTrace();
		}
		
		if(client != null){
			System.out.println("cliente inicializado...");
			
			//Inicializa a thread do cliente
			new Thread(client).start();									
			
			
			try {
				//TODO: Teste
				//Player player = new Player();
				//player.setName("Eduardo");
				client.createNewGame("Coisinha Lindia", player);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	public String getPlayerName(){
		return this.player.getName();
	}
	
	public boolean removeGame(int gameId){
		try {
			return server.removeGame(gameId);
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		
		return false;
	}
}